package GUI;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyVetoException;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;

import spreadsheet.Cell;
import spreadsheet.Spreadsheet;

public class SpreadSheetFrame extends JInternalFrame{
	/**
	 * An JInternalFrame that will hold a spreadsheet.
	 */
	private JInternalFrame my_frame;
	/**
	 * The number of rows in the newly created spreadsheet.
	 */
	private int my_rows;
	/**
	 * The number of columns in the newly created spreadsheet.
	 */
	private int my_columns;
	/**
	 * The height of the column labels.
	 */
	private final int my_column_label_height = 15;
	/**
	 * The width of the row Labels.
	 */
	private final int my_row_label_width = 50;
	/**
	 * The GUI that holds the SpreadSheetFrames.
	 */
	private GUI my_gui;
	/**
	 * The spreadsheet that is used to build the SpreadSheetFrame.
	 */
	private Spreadsheet my_spreadsheet;
	/**
	 * Records if the "enter" key was used to update the current cell.
	 */
	private boolean wasEnterPressed = false;
	/**
	 * A reference to this SpreadSheetFrame, used in ActionListeners
	 */
	private SpreadSheetFrame myself;

	/**
	 * Public constructor for the SpreadSheetFrame.
	 * @param the_rows The number of rows in the spreadsheet.
	 * @param the_columns The number of columns in the spreadsheet.
	 * @param the_gui The GUI that the speadsheet belongs to.
	 */
	public SpreadSheetFrame(int the_rows, int the_columns, GUI the_gui) {
		my_gui = the_gui;
		my_rows = the_rows;
		my_columns = the_columns;
		my_spreadsheet = new Spreadsheet(my_rows, my_columns);
		myself = this;
		my_frame = new JInternalFrame("New SpreadSheetFrame", false, true, true, true);
		my_frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		my_frame.addInternalFrameListener(new closeAction());
		my_frame.setVisible(true);
		my_frame.setJMenuBar(createMenuBar());
		my_frame.add(createSpreadSheetPanel());
		my_frame.pack();
	}
	/**
	 * Public constructor for creating a new SpreadSheetFrame when the resize button is clicked.
	 * @param the_rows The number of rows in the spreadsheet.
	 * @param the_columns The number of columns in the spreadsheet.
	 * @param the_gui The GUIthat the spreadsheet belongs to.
	 * @param the_title The title of the spreadsheet.
	 * @param the_spreadsheet The spreadsheet that the SpreadSheetFrame will represent.
	 */
	public SpreadSheetFrame(int the_rows, int the_columns, GUI the_gui, String the_title, Spreadsheet the_spreadsheet) {
		my_gui = the_gui;
		my_rows = the_rows;
		my_columns = the_columns;
		my_spreadsheet = the_spreadsheet;
		myself = this;
	
		my_frame = new JInternalFrame(the_title, false, true, true, true);
		my_frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		my_frame.addInternalFrameListener(new closeAction());
		my_frame.setVisible(true);
		my_frame.setJMenuBar(createMenuBar());
		my_frame.add(createSpreadSheetPanel());

		my_frame.pack();
	}

	/**
	 * Returns the JInternalFrame in the SpreadSheetFrame.
	 * @return my_frame
	 */
	public JInternalFrame getFrame() {
		return my_frame;
	}
	/**
	 * Creates the JMenubar for the JInternalFrame
	 * @return menuBar The new JMenubar for the JInternalFrame.
	 */
	private JMenuBar createMenuBar() {
		// creates the items in the File menu
		JMenuBar menuBar = new JMenuBar();
		JMenu fileMenu = new JMenu("File");
		JMenuItem closeItem = new JMenuItem("Close");
		// Creates the ActionListener for closing a SpreadSheetFrame
		closeItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				my_gui.getSpreadSheets().remove(myself);
				try {
					my_frame.setClosed(true);
				} catch (PropertyVetoException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});
		fileMenu.add(closeItem);
		menuBar.add(fileMenu);
		return menuBar;
	}
	/**
	 * Creates a panel that will hold the information in the spreadsheet.
	 * @return spreadSheetPanel A JPanel that will hold the info in the spreadsheet.
	 */
	private JPanel createSpreadSheetPanel() {
		JPanel spreadSheetPanel = new JPanel();
		//spreadSheetPanel.setSize(my_min_size);
		spreadSheetPanel.setLayout(new BoxLayout(spreadSheetPanel, BoxLayout.Y_AXIS));
		// creates the top panel with the select all button and column labels
		JPanel topPanel = new JPanel();
		topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
		JLabel selectAll = new JLabel();
		selectAll.setPreferredSize(new Dimension(my_row_label_width, my_column_label_height));
		selectAll.setMaximumSize(new Dimension(my_row_label_width, my_column_label_height));
		selectAll.setMinimumSize(new Dimension(my_row_label_width, my_column_label_height));
		selectAll.setBackground(Color.LIGHT_GRAY);
		selectAll.setBorder(BorderFactory.createLineBorder(Color.black, 2));
		topPanel.add(selectAll);
		final StringBuilder sb = new StringBuilder();
		Dimension tempDim = new Dimension(my_gui.getColumnWidth(), my_column_label_height);
		int i = 1;
		for(; i <= my_columns; i++ ){
			sb.delete(0, sb.length());
			columnText(i, sb);
			JLabel tempLabel = new JLabel(sb.toString());
			tempLabel.setHorizontalAlignment(JLabel.CENTER);
			tempLabel.setPreferredSize(tempDim);
			tempLabel.setMaximumSize(tempDim);
			tempLabel.setMinimumSize(tempDim);
			tempLabel.setBorder(BorderFactory.createLineBorder(Color.black, 2));
			tempLabel.setBackground(Color.LIGHT_GRAY);
			topPanel.add(tempLabel);
		}
		spreadSheetPanel.add(topPanel);	
		// create the individual rows of the spreadsheet
		tempDim = new Dimension(my_gui.getColumnWidth(), my_gui.getRowHeight());
		Dimension rowLabelDim = new Dimension(my_row_label_width, my_gui.getRowHeight());

		i = 1; // resets i to 1 for creating rows
		for(; i <= my_rows; i++ ) {
			JPanel tempPanel = new JPanel();
			tempPanel.setLayout(new BoxLayout(tempPanel, BoxLayout.X_AXIS));
			JLabel rowLabel = new JLabel(Integer.toString(i));
			rowLabel.setHorizontalAlignment(JLabel.CENTER);
			rowLabel.setMinimumSize(rowLabelDim);
			rowLabel.setMaximumSize(rowLabelDim);
			rowLabel.setBorder(BorderFactory.createLineBorder(Color.black, 2));
			rowLabel.setBackground(Color.lightGray);
			tempPanel.add(rowLabel);
			// for loop creates the individual cells and JTextField that will graphically represent them.
			for(int j = 1; j <= my_columns; j++){
				final JTextField tempText = new JTextField();
				tempText.setMinimumSize(tempDim);
				tempText.setMaximumSize(tempDim);
				tempText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
				tempPanel.add(tempText);
				final Cell tempCell = my_spreadsheet.getCell(i, j);
				tempCell.setTextField(tempText);
				// used if resizing a SpreadsheetFrame
				if (tempCell.getFormula() != null){
					tempText.setText(tempCell.getCellValue());
				}

				// need for mouseListener
				final int row = i;
				final int column = j;

				// add actionlisten for when "enter" is pressed
				tempText.addActionListener(new ActionListener() {

					@Override
					public void actionPerformed(ActionEvent arg0) {
						// TODO Auto-generated method stub
						my_gui.setCurrentCell(tempCell);
						my_gui.setCurrentTextField(tempText);
						my_gui.getCurrentCell().setFormula(tempText.getText());
						my_gui.evaluateCurrent();
						my_gui.getCurrentTextField().setText(my_gui.getCurrentCell().getCellValue());
						wasEnterPressed = true;
					}});
				tempText.addKeyListener(new KeyListener() {
					@Override
					public void keyPressed(KeyEvent e) {
						if(e.getKeyCode() == KeyEvent.VK_SHIFT) {
							my_gui.setShift(true);
						}
						
					}
					@Override
					public void keyReleased(KeyEvent e) {
						if(e.getKeyCode() == KeyEvent.VK_SHIFT && my_gui.isShift()) {
							my_gui.setShift(false);
						}
					}
					@Override
					public void keyTyped(KeyEvent arg0) {
						// TODO Auto-generated method stub
						
					}
				});
				
				// add mouseListener for when a cell is clicked
				tempText.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent me) {
							// evaluates previously selected cell
							if(my_gui.getCurrentCell() != null) {
								if(wasEnterPressed) {
									wasEnterPressed = false; 
								} else {
								my_gui.getCurrentCell().setFormula(my_gui.getCurrentTextField().getText());
								}
								my_gui.evaluateCurrent();
								my_gui.getCurrentTextField().setText(my_gui.getCurrentCell().getCellValue());
								my_frame.validate();
							}
							// mouse + shift; add to and evaluate function stuff
							if(my_gui.isShift()){ 
								if(tempCell.getCellValue() != null) {
									tempText.setBackground(Color.getHSBColor(211, 22, 100));
									if(!my_gui.getFunctionPanel().getFields().contains(tempText)) {
										my_gui.getFunctionPanel().getFields().add(tempText);
									}
									my_gui.getFunctionPanel().evaluateFunction();
									my_frame.validate();
								}
							} else {
							my_gui.getFunctionPanel().killFunction();
							my_gui.setCurrentCell(tempCell);
							my_gui.setCurrentTextField(tempText);
							// displays cell formula
							tempText.setText(tempCell.getFormula());

							// sets text in infoPanel
							sb.delete(0, sb.length());
							columnText(column, sb);
							String labelText = sb.toString() + Integer.toString(row);
							my_gui.getInfoPanel().setCellLabel(labelText);
							// would like to change this to display formula.
							my_gui.getInfoPanel().setCellText(my_gui.getCurrentCell().getFormula());
							}
					}

				});

			}
			spreadSheetPanel.add(tempPanel);
		}
		return spreadSheetPanel;
	}
	/**
	 * Creates the text for a column label based on an integer.
	 * @param the_int The integer that represent the column.
	 * @param the_sb The StringBuilder that will hold the string representation of the column.
	 */
	private void columnText(int the_int, StringBuilder the_sb){
		// base case the_int is less than or equal to 26
		if(the_int <= 26 && the_int > 0){
			the_sb.append((char) (the_int + 64));
			return;
		}
		if(the_int % 26 == 0) {
			columnText((the_int/26) -1, the_sb);
			the_sb.append("Z");

		} else { 
			columnText(the_int/26, the_sb);
			the_sb.append((char) (the_int % 26 + 64));
		}
	}
	/**
	 * The number of rows in the SpreadSheetFrame.
	 * @return my_rows
	 */
	public int getRows() {
		return my_rows;
	}
	/**
	 * The number of columns in the SpreadSheetFrame.
	 * @return my_columns
	 */
	public int getColumns() {
		return my_columns;
	}
	/**
	 * Gets the spreadsheet that the SpreadSheetFrame represents.
	 * @return my_spreadsheet
	 */
	public Spreadsheet getSpreadsheet() {
		return my_spreadsheet;
	}
	/**
	 * A class that creates the ActionListener for when a SpreadSheetFrame is closed.
	 * Only implements the internalFrameClosed method.
	 * @author abrahamsantini
	 *
	 */
	private class closeAction implements InternalFrameListener {

		@Override
		public void internalFrameActivated(InternalFrameEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void internalFrameClosed(InternalFrameEvent arg0) {
			my_gui.getSpreadSheets().remove(myself);
			//my_frame.dispose();
			
		}

		@Override
		public void internalFrameClosing(InternalFrameEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void internalFrameDeactivated(InternalFrameEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void internalFrameDeiconified(InternalFrameEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void internalFrameIconified(InternalFrameEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void internalFrameOpened(InternalFrameEvent arg0) {
			// TODO Auto-generated method stub
			
		}
		
	}
}
